import 'dart:async';
import 'dart:io';

import 'package:jet_rails/jr_services/jr_apis.dart';
import 'package:jet_rails/jr_services/jr_services.dart';
import 'package:jet_rails/jr_utils/extensions/jr_string_extension.dart';
import 'package:jet_rails/jr_utils/jr_device.dart';
import 'package:jet_rails/jr_utils/jr_logger.dart';

class JrTrackingHeadersKey {
  static const String tracerData = "data";
  static const String tracerLogType = "log_type";
  static const String tracerSubtype = "subtype";
  static const String tracerBehavior = "behavior";
  static const String tracerDeviceId = "device-id";
  static const String tracerAndroidId = "android_id";
  static const String tracerUserId = "user_id";
  static const String tracerPkg = "pkg";
  static const String tracerChnId = "chn_id";
  static const String tracerVer = "ver";
  static const String tracerPlatform = "platform";
  static const String tracerModel = "model";
  static const String tracerPVer = "p_ver";
  static const String tracerLanId = "lan_id";
  static const String tracerSecId = "sec_id";
  static const String tracerUtmSource = "utm_source";
  static const String tracerAfAdgroupId = "af_adgroup_id";
  static const String tracerAfAdset = "af_adset";
  static const String tracerAfAdsetId = "af_adset_id";
  static const String tracerAfStatus = "af_status";
  static const String tracerAfAgency = "af_agency";
  static const String tracerAfChannel = "af_channel";
  static const String tracerAfCampaign = "campaign";
  static const String tracerAfCampaignId = "campaign_id";
  static const String tracerCountry = "country";
  static const String tracerSysLan = "sys_lan";
}

class JrTrackingPages {
  static const String pageLaunch = 'launch';
  static const String pageQuickLogin = 'quicklogin';
  static const String pageAppleLogin = 'applelogin';
  static const String pagePrivacy = 'privacy';
  static const String pageLoginSuccess = 'loginsuccess';
  static const String pagePurchase = 'purchase';
  static const String pageCreateOrder = 'createorder';
  static const String pageEditAvatar = 'editavatar';
  static const String pageLogout = 'logout';
  static const String pageDeleteAccount = 'deleteaccount';
  static const String pageCustomer = 'customer';
  static const String pageTerms = 'terms';
  static const String pageReport = 'report';
  static const String pageBlock = 'block';
}

class JrTrackingManger {
  static const String _event = 'event';
  static const String _tm = 'tm';
  static const String _page = 'page';
  static const String _subPage = 'subPage';
  static const String _terPage = 'terPage';
  static const String _broadcasterId = 'broadcasterId';
  static const String _duration = 'duration';

  static void start({String? page, String? subPage, String? terPage, String? broadcasterId}) {
    var map = <String, dynamic>{};
    if (page != null) map[_page] = page;
    if (subPage != null) map[_subPage] = subPage;
    if (terPage != null) map[_terPage] = terPage;
    if (broadcasterId != null) map[_broadcasterId] = broadcasterId;

    map[_duration] = 0;
    map[_event] = 'pv';
    map[_tm] = DateTime.now().millisecondsSinceEpoch;

    JrTracking.put(JrTrackingType.globalBehavior, map);
    JrLogger.d('start: $map');
  }
}

enum JrTrackingType {
  globalBehavior('event', 'global_behavior', 'event'),
  clickEvent("event", "click", "event");

  final String logType, subType, behavior;

  const JrTrackingType(this.logType, this.subType, this.behavior);
}

class JrTracking {
  static const int uploadBatchLimitSize = 20;

  static bool _isWaitingForSendCache = false;
  static List<Map<String, dynamic>> cacheList = [];

  static void click(String page) => JrTracking.put(JrTrackingType.clickEvent, {'page': page});

  static void put(JrTrackingType type, Map<String, dynamic> event) {
    if (event.isEmpty) {
      return;
    }
    cacheList.insert(0, _newItemData(type.logType, type.subType, type.behavior, event));
    uploadDelayed();
  }

  static void putImmediately(JrTrackingType logType, Map<String, dynamic> event) {
    if (event.isEmpty) {
      return;
    }
    List<Map<String, dynamic>> list = [_newItemData(logType.logType, logType.subType, logType.behavior, event)];
    _doUpload(list, false);
  }

  static void uploadDelayed() {
    if (_isWaitingForSendCache) {
      return;
    }
    _isWaitingForSendCache = true;
    Timer(const Duration(milliseconds: 3000), () {
      _isWaitingForSendCache = false;
      uploadCache(false);
    });
  }

  static void uploadCache(bool forceUploadAll) {
    try {
      if (cacheList.isEmpty) {
        return;
      }
      int limit = uploadBatchLimitSize;
      List<Map<String, dynamic>> sendList = [];
      if (cacheList.length >= limit && !forceUploadAll) {
        sendList.addAll(cacheList.sublist(0, limit));
        cacheList.removeRange(0, limit);
      } else {
        sendList.addAll(cacheList);
        cacheList.clear();
      }
      _doUpload(sendList, true);
    } catch (e, s) {
      JrLogger.e('upload failed: $e\n$s');
    }
  }

  static Future<void> _doUpload(List<Map<String, dynamic>> sendList, bool isContinue) async {
    try {
      await JrApis.eventTracking(sendList);
      if (isContinue) {
        uploadDelayed();
      }
    } catch (e, s) {
      JrLogger.e('Tracer data upload failed: $e\n$s');
    }
  }

  /// trace list item data
  static int _serialId = 0;

  static final String _launcherId = '${DateTime.now().millisecondsSinceEpoch}${JrDevice.deviceId}'.MD5;

  static Map<String, dynamic> _newItemData(
    String logType,
    String subType,
    String behavior,
    Map<String, dynamic>? event,
  ) {
    String platform = Platform.isIOS ? 'iOS' : 'Android';
    String model = JrDevice.model;
    String userId = JrServices.instance.loginUser.value.userId ?? '';
    String country = JrServices.instance.loginUser.value.country ?? '';
    Map<String, dynamic> itemData = {};
    itemData[JrTrackingHeadersKey.tracerData] = [event];
    itemData[JrTrackingHeadersKey.tracerLogType] = "event";
    itemData[JrTrackingHeadersKey.tracerSubtype] = "global_behavior";
    itemData[JrTrackingHeadersKey.tracerBehavior] = "event";
    itemData[JrTrackingHeadersKey.tracerDeviceId] = JrDevice.deviceId;
    itemData[JrTrackingHeadersKey.tracerUserId] = userId;
    itemData[JrTrackingHeadersKey.tracerPkg] = JrDevice.packageName;
    itemData[JrTrackingHeadersKey.tracerChnId] = '';
    itemData[JrTrackingHeadersKey.tracerVer] = JrDevice.version;
    itemData[JrTrackingHeadersKey.tracerPlatform] = platform;
    itemData[JrTrackingHeadersKey.tracerModel] = model;
    itemData[JrTrackingHeadersKey.tracerPVer] = JrDevice.build;
    itemData[JrTrackingHeadersKey.tracerLanId] = _launcherId;
    itemData[JrTrackingHeadersKey.tracerSecId] = _serialId++;
    itemData[JrTrackingHeadersKey.tracerSysLan] = JrDevice.language;
    itemData[JrTrackingHeadersKey.tracerCountry] = country;
    itemData["tm"] = DateTime.now().millisecondsSinceEpoch;
    return itemData;
  }
}
